/*
 * MusicLabs, Copyright (C) 2008-2009 Felippe Ragghianti
 * http://code.google.com/p/musiclabs
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */

// NOTE: pressure signature could also be used in separate layer, for example.

package br.com.music.rhythm;

import br.com.music.Duration;
import br.com.music.utils.Logger;
import java.util.Vector;

// TODO FIXME XXX in order to make possible simple instantiations of odd
// time signatures, like 5/N for example, we'll need to change the API.

/**
 *
 */
public class TimeSignature {

    // binary time marks.
    public static final int DUPLE               = 2;
    public static final int BINARY              = 2;
    public static final int DUPLE_COMPOUND      = 6;
    public static final int BINARY_COMPOUND     = 6;

    // ternary time marks.
    public static final int TRIPLE              = 3;
    public static final int TERNARY             = 3;
    public static final int TRIPLE_COMPOUND     = 9;
    public static final int TERNARY_COMPOUND    = 9;

    // quaternary time marks.
    public static final int QUADRUPLE           = 4;
    public static final int QUATERNARY          = 4;
    public static final int QUADRUPLE_COMPOUND  = 12;
    public static final int QUATERNARY_COMPOUND = 12;

    private int type;
    private Vector<Beat> beats;
    private Duration duration;


    /**
     * Class constructor.
     *
     * @param beats
     * @param noteValue
     */
    public TimeSignature(int beats,  Duration duration) throws Exception {
        this.type = beats;
        this.duration = duration;
        this.beats = TimeSignature.IntegerToBeats(beats, duration);
    }

    /**
     * Class constructor.
     *
     * @param ratio An array of two ints containing the number of beats and
     * note value respectively.
     */
    public TimeSignature(int beats) throws Exception {
        this.type = beats;
        this.duration = br.com.music.utils.RuntimeSettings.DefaultDuration;
        this.beats = TimeSignature.IntegerToBeats(beats, duration);
    }

    /**
     * Vararg constructor.
     * 
     * @note This is the only constructor that never throws exception,
     * because it takes any beat sequence for granted.
     * 
     * @param beats Vector of <code><@link Beats></code>.
     */
    public TimeSignature(Beat... beats) {
        this.type = beats.length;
        this.beats = new Vector<Beat>();
        for(Beat beat : beats) {
            this.beats.add(beat);
        }
    }

    /**
     * Returns this time signature as String. 
     *
     * @note Since TimeSignature is not Playable we're free to use toString for
     * other purposes other than generating JFugue playable text.
     *
     * @return A string describing this time signature. For a TimeSignature(
     * TimeSignature.BINARY, Duration.CROTCHET), for example, the returned 
     * String would be "2/4", and so on.
     */
    @Override
    public String toString() {
        return this.type +"/"+ this.duration;
    }

    /**
     * Get the sequence of beats that represents this Time Signature.
     * 
     * @return A Vector of Beats representing a time signature.
     */
    public Vector<Beat> getBeats() {
        return this.beats;
    }

    /**
     * Convert from <code>{@link Integer}</code> to <code>{@link Vector}</code> 
     * of <code>{@link Beats}</code>.
     *
     * @param n Number of beats in a time signature as integer.
     * @return A vector of <code>{@link Beats}</code>.
     * @throws java.lang.Exception
     */
    public static Vector<Beat> IntegerToBeats(Integer n, Duration duration)
            throws Exception
    {
        Vector<Beat> beats = new Vector<Beat>();
        
        switch(n) {
            case 1: // to ease semantics and help the metronome
                Logger.trace("Single/Unary time signature pattern created.");
                beats.add(new Beat(Beat.STRONG, duration));
                break;

            case 2: // fall through
            case 6:
                Logger.trace("Duple/binary time signature pattern created.");
                beats.add(new Beat(Beat.STRONG, duration));
                beats.add(new Beat(Beat.WEAK, duration));
                break;

            case 3: // fall through
            case 9:
                Logger.trace("Triple/ternary time signature pattern created.");
                beats.add(null);
                beats.add(new Beat(Beat.STRONG, duration));
                beats.add(new Beat(Beat.WEAK, duration));
                beats.add(new Beat(Beat.WEAK, duration));
                break;

            case 4: // fall through
            case 12:
                Logger.trace("Quadruple/quaternary time signature pattern created.");
                beats.add(new Beat(Beat.STRONG, duration));
                beats.add(new Beat(Beat.WEAK, duration));
                beats.add(new Beat(Beat.MEDIUM, duration));
                beats.add(new Beat(Beat.WEAK, duration));
                break;

            default: throw new Exception("Can't generate beat sequence. Try " +
                    "using a composition of TimeSignatures in cases like " +
                    "quintuple signatures, for example."); // TODO: create package Exception
                
        }
        return beats;
    }

}

